module;

#include <boost/asio/ip/tcp.hpp>

export module Sensor;
import std;
import Config;
import <boost/json.hpp>;

using namespace boost;
using tcp = asio::ip::tcp;

export namespace Sensor {
	class Client {
	private:
		std::string sensor_server_ip = "192.168.0.7";
		std::string sensor_server_port = "8080";
		std::ostream& log = std::clog;
		std::ostream& err = std::cerr;
		tcp::iostream stream_sensor;
		std::stack<char> stack;
	public:
		bool tryConnect() {
			log << Config::try_connect << std::endl;
			stream_sensor = tcp::iostream(sensor_server_ip, sensor_server_port);
			if (!stream_sensor) {
				err << Config::bad_connect << std::endl;
				return false;
			}
			log << Config::yes_connect << std::endl;
			return true;
		}
		void checkGetChar(const char c) {
			if (c == '{' || c == '[') {
				stack.push(c);
				return;
			}
			else if (!(c == '}' || c == ']')) {
				return;
			}
			char stack_c = stack.top();
			if (c == '}' && stack_c == '{')
				stack.pop();
			else if (c == ']' && stack_c == '[')
				stack.pop();
			else
				stack.push(c);

		}
		std::string readOne() {
			std::string cache;
			while (true) {
				char c = stream_sensor.get();
				if (!stream_sensor)
					break;
				checkGetChar(c);
				cache += c;
				if (stack.empty() == true)
					return cache;
			}
			return "";
		}
		static json::array getDataArr(std::string json_str) noexcept(false) {
			json::value json_raw = json::parse(json_str);
			json::object json_params = json_raw.as_object()["params"].as_object();
			json::array json_dataArr = json_params["r_data"].as_array();
			return json_dataArr;
		}
		void start() {
			if (tryConnect() == false)
				return;
			while (true) {
				if (!stream_sensor)
					break;
				try {
					json::array json_dataArr = getDataArr(readOne());
					for (const auto& dataValue : json_dataArr) {
						const auto& dataObj = dataValue.as_object();
						if (dataObj.at("err").as_string() != "0") {
							err << "err: " << dataObj.at("err") << " ";
							continue;
						}
						std::cout << dataObj << " ";
					}
					std::cout << std::endl;
					//std::cout << json::serialize(json_dataArr) << std::endl;
				}
				catch (const std::exception& e) {
					err << e.what() << std::endl;
				}
			}
		}
	};
}